package com.axend.lib_base.utils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class BitmapToVideo {

    private static final String TAG = "BitmapToVideo";
    private MediaMuxer mMuxer;
    private MediaCodec mEncoder;
    private int mTrackIndex;
    private boolean mMuxerStarted;
    private int mWidth;
    private int mHeight;
    private int mBitRate;
    private int mFrameRate;
    private int mIFrameInterval;
    private Surface mInputSurface;

    public BitmapToVideo(int width, int height, int bitRate, int frameRate, int iFrameInterval) {
        mWidth = width;
        mHeight = height;
        mBitRate = bitRate;
        mFrameRate = frameRate;
        mIFrameInterval = iFrameInterval;
    }

    public void startRecording(String outputPath) throws IOException {
        try {
        mMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, mWidth, mHeight);
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
        format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, mIFrameInterval);

        mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
        mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mInputSurface = mEncoder.createInputSurface();

        mEncoder.start();
        mTrackIndex = -1;
        mMuxerStarted = false;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

//    public void stopRecording() {
//        if (mEncoder != null) {
//            mEncoder.signalEndOfInputStream();
//            drainEncoder(true);
//            mEncoder.stop();
//            mEncoder.release();
//            mEncoder = null;
//        }
//
//        if (mMuxer != null) {
//            mMuxer.stop();
//            mMuxer.release();
//            mMuxer = null;
//        }
//    }
    public void stopRecording() {
        if (mEncoder != null) {
            try {
//                // 通知编码器输入流结束
//                mEncoder.signalEndOfInputStream();
                // 排空编码器
                drainEncoder(true);
                // 停止编码器
                mEncoder.stop();
                // 释放编码器资源
                mEncoder.release();
            } catch (Exception e) {
                Log.e(TAG, "Error stopping encoder: " + e.getMessage(), e);
            } finally {
                mEncoder = null;
            }
        }

        if (mMuxer != null) {
            try {
                // 停止 Muxer
                mMuxer.stop();
                // 释放 Muxer 资源
                mMuxer.release();
            } catch (Exception e) {
                Log.e(TAG, "Error stopping Muxer: " + e.getMessage(), e);
            } finally {
                mMuxer = null;
            }
        }

        // 释放输入 Surface
        if (mInputSurface != null) {
            mInputSurface.release();
            mInputSurface = null;
        }
    }

    public void addFrame(Bitmap bitmap) {
        if (mEncoder == null) {
            Log.e(TAG, "Encoder not initialized");
            return;
        }

        long startTimestampUs = computePresentationTimeUs(System.currentTimeMillis());

        drawBitmapToSurface(bitmap, startTimestampUs);
        drainEncoder(false);
    }

//    private void drawBitmapToSurface(Bitmap bitmap, long presentationTimeUs) {
//        if (mInputSurface == null) {
//            Log.e(TAG, "Input surface not initialized");
//            return;
//        }
//
//        android.graphics.Canvas canvas = null;
//        try {
//            canvas = mInputSurface.lockCanvas(null);
//            if (canvas != null) {
//                canvas.drawColor(0, PorterDuff.Mode.CLEAR); // Clear the surface
//                canvas.drawBitmap(bitmap, 0, 0, null);
//            }
//        } finally {
//            if (canvas != null) {
//                mInputSurface.unlockCanvasAndPost(canvas);
//            }
//        }
//
//        mEncoder.queueInputBuffer(0, 0, 0, presentationTimeUs, 0);
//    }
private void drawBitmapToSurface(Bitmap bitmap, long presentationTimeUs) {
    // 获取输入 Surface 的 Canvas
    Canvas canvas = mInputSurface.lockCanvas(null);
    if (canvas == null) {
        Log.e(TAG, "Failed to lock canvas");
        return;
    }
    try {
        // 清除画布
        canvas.drawColor(Color.BLACK);
        // 将 Bitmap 绘制到 Surface 上
        canvas.drawBitmap(bitmap, null, new Rect(0, 0, mWidth, mHeight), null);
    } finally {
        // 解锁并提交画布
        mInputSurface.unlockCanvasAndPost(canvas);
    }
}

    private void drainEncoder(boolean endOfStream) {
        if (endOfStream) {
            mEncoder.signalEndOfInputStream();
        }

        ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        boolean isEos = false;
        int retryCount = 0;
        final int MAX_RETRIES = 10; // 设置最大重试次数

        while (!isEos && retryCount < MAX_RETRIES) {
            int outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 1000); // 调整超时时间
            switch (outputBufferIndex) {
                case MediaCodec.INFO_TRY_AGAIN_LATER:
                    // 没有可用的输出缓冲区，继续等待
                    retryCount++;
                    break;
                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                    if (mMuxerStarted) {
                        throw new RuntimeException("Format changed twice");
                    }
                    mTrackIndex = mMuxer.addTrack(mEncoder.getOutputFormat());
                    mMuxer.start();
                    mMuxerStarted = true;
                    break;
                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                    encoderOutputBuffers = mEncoder.getOutputBuffers();
                    break;
                default:
                    ByteBuffer encodedData = encoderOutputBuffers[outputBufferIndex];
                    if (encodedData == null) {
                        throw new RuntimeException("encoderOutputBuffer " + outputBufferIndex + " was null");
                    }
                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                        bufferInfo.size = 0;
                    }
                    if (bufferInfo.size != 0) {
                        if (!mMuxerStarted) {
                            throw new RuntimeException("Muxer not started");
                        }
                        encodedData.position(bufferInfo.offset);
                        encodedData.limit(bufferInfo.offset + bufferInfo.size);
                        mMuxer.writeSampleData(mTrackIndex, encodedData, bufferInfo);
                    }
                    mEncoder.releaseOutputBuffer(outputBufferIndex, false);
                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                        isEos = true;
                    }
                    break;
            }
        }

        if (retryCount >= MAX_RETRIES) {
            Log.w(TAG, "Reached max retries in drainEncoder, exiting loop");
        }

        if (endOfStream) {
            // 确保所有数据都已写入 MediaMuxer
            while (true) {
                int outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 1000);
                if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
                    break;
                }
                if (outputBufferIndex >= 0) {
                    ByteBuffer encodedData = encoderOutputBuffers[outputBufferIndex];
                    if (encodedData == null) {
                        throw new RuntimeException("encoderOutputBuffer " + outputBufferIndex + " was null");
                    }
                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                        bufferInfo.size = 0;
                    }
                    if (bufferInfo.size != 0) {
                        if (!mMuxerStarted) {
                            throw new RuntimeException("Muxer not started");
                        }
                        encodedData.position(bufferInfo.offset);
                        encodedData.limit(bufferInfo.offset + bufferInfo.size);
                        mMuxer.writeSampleData(mTrackIndex, encodedData, bufferInfo);
                    }
                    mEncoder.releaseOutputBuffer(outputBufferIndex, false);
                }
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    break;
                }
            }
        }
    }

//    private void drainEncoder(boolean endOfStream) {
//        if (endOfStream) {
//            mEncoder.signalEndOfInputStream();
//        }
//
//        ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
//        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
//        boolean isEos = false;
//
//        while (!isEos) {
//            int outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 10000);
//            switch (outputBufferIndex) {
//                case MediaCodec.INFO_TRY_AGAIN_LATER:
//                    // 没有可用的输出缓冲区，继续等待
//                    if (endOfStream) {
//                        break; // 如果已经是最后一帧，退出循环
//                    }
//                    break;
//                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
//                    if (mMuxerStarted) {
//                        throw new RuntimeException("Format changed twice");
//                    }
//                    mTrackIndex = mMuxer.addTrack(mEncoder.getOutputFormat());
//                    mMuxer.start();
//                    mMuxerStarted = true;
//                    break;
//                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
//                    encoderOutputBuffers = mEncoder.getOutputBuffers();
//                    break;
//                default:
//                    ByteBuffer encodedData = encoderOutputBuffers[outputBufferIndex];
//                    if (encodedData == null) {
//                        throw new RuntimeException("encoderOutputBuffer " + outputBufferIndex + " was null");
//                    }
//                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
//                        bufferInfo.size = 0;
//                    }
//                    if (bufferInfo.size != 0) {
//                        if (!mMuxerStarted) {
//                            throw new RuntimeException("Muxer not started");
//                        }
//                        encodedData.position(bufferInfo.offset);
//                        encodedData.limit(bufferInfo.offset + bufferInfo.size);
//                        mMuxer.writeSampleData(mTrackIndex, encodedData, bufferInfo);
//                    }
//                    mEncoder.releaseOutputBuffer(outputBufferIndex, false);
//                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
//                        isEos = true;
//                    }
//                    break;
//            }
//        }
//    }


//    private void drainEncoder(boolean endOfStream) {
//        if (mEncoder == null) {
//            Log.e(TAG, "Encoder not initialized");
//            return;
//        }
//
//        if (endOfStream) {
//            mEncoder.signalEndOfInputStream();
//        }
//
//        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
//        while (true) {
//            int encoderStatus = mEncoder.dequeueOutputBuffer(bufferInfo, 10000);
//            if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
//                if (endOfStream) {
//                    break;
//                } else {
//                    return;
//                }
//            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
//                if (mMuxerStarted) {
//                    throw new RuntimeException("format changed twice");
//                }
//                mTrackIndex = mMuxer.addTrack(mEncoder.getOutputFormat());
//                mMuxer.start();
//                mMuxerStarted = true;
//            } else if (encoderStatus < 0) {
//                Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
//            } else {
//                ByteBuffer encodedData = mEncoder.getOutputBuffer(encoderStatus);
//                if (encodedData == null) {
//                    throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
//                }
//
//                if (bufferInfo.size != 0) {
//                    if (!mMuxerStarted) {
//                        throw new RuntimeException("muxer hasn't started");
//                    }
//
//                    encodedData.position(bufferInfo.offset);
//                    encodedData.limit(bufferInfo.offset + bufferInfo.size);
//                    mMuxer.writeSampleData(mTrackIndex, encodedData, bufferInfo);
//                }
//
//                mEncoder.releaseOutputBuffer(encoderStatus, false);
//
//                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
//                    break;
//                }
//            }
//        }
//    }

    private long computePresentationTimeUs(long timestampMs) {
        return timestampMs * 1000L;
    }
}
